package com.shawn.admin.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.unit.DataUnit;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shawn.admin.mapper.AnalysisMapper;
import com.shawn.admin.mapper.LogMapper;
import com.shawn.autoconfig.properties.DistributionProperties;
import com.shawn.commons.utils.DateUtils;
import com.shawn.commons.utils.RC;
import com.shawn.dubbo.api.UserApi;
import com.shawn.dubbo.api.UserInfoApi;
import com.shawn.model.entity.*;
import com.shawn.model.vo.AnalysisVo;
import com.shawn.model.vo.DayDataVo;
import com.shawn.model.vo.DistributionVo;
import com.shawn.model.vo.YearDateVo;
import org.apache.dubbo.config.annotation.DubboReference;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author shawn
 * @date 2022年 11月 09日 17:21
 */
@Service
public class DashBoardService {

    @Autowired
    private AnalysisMapper analysisMapper;

    @Autowired
    private LogMapper logMapper;
    @Resource
    private DistributionProperties distributionProperties;
    @DubboReference
    private UserApi userApi;


    @DubboReference
    private UserInfoApi userInfoApi;

    /**
     * 得到分析结果
     *
     * @return {@link AnalysisVo}
     */
    public AnalysisVo getAnalysisResults() {
        //获取累计注册人数
        Integer cumulativeUsers = userApi.getUserNum();
        //连续三十天每天都登录的用户 查找当日日期与30天前的日期
        SimpleDateFormat format = new SimpleDateFormat(RC.GENERAL_DATE_FORMAT);
        long now = System.currentTimeMillis();
        String today = format.format(now);
        //昨天
        long yesterdayTime = DateUtil.yesterday().getTime();
        String yesterday = format.format(yesterdayTime);

        //前天
        long day2 = now - 2 * 24 * 3600 * 1000L;
        String theDayBeforeYesterday = format.format(day2);

        long day30 = now - 30 * 24 * 3600 * 1000L;
        String day30Ago = format.format(day30);
        //三十天内的活跃用户
        Integer activePassMonth = logMapper.activeByDays(day30Ago, today, 30);

        long weekAgo = now - 7 * 24 * 3600 * 1000L;
        String weekAgoDate = format.format(weekAgo);
        //一周内活跃用户
        Integer activePassWeek = logMapper.activeByDays(weekAgoDate, today, 7);
        //获取今日注册用户
        Integer newUsersToday = logMapper.registerNumToday(today);
        //获取昨日注册用户
        Integer newUsersYesterday = logMapper.registerNumToday(yesterday);
        //新增用户增长率

        //昨日注册用户数
        Integer yesterdayRegisters = logMapper.registerNumToday(yesterday);
        //增长率
        Integer newUsersTodayRate = yesterdayRegisters == 0 ? 0 : (newUsersToday - yesterdayRegisters) / yesterdayRegisters * 100;

        //登录频次
        Integer loginTimesToday = logMapper.loginTimesToday(today);
        Integer loginTimesYesterday = logMapper.loginTimesToday(yesterday);
        //同比增长率
        Integer loginTimesTodayRate = loginTimesYesterday == 0 ? 0 : (loginTimesToday - loginTimesYesterday) / loginTimesYesterday * 100;

        //当日日活
        Integer loginNumToday = logMapper.loginNumToday(today);
        int activeUsersToday = newUsersToday + loginNumToday;
        //日活同比
        //1 昨日登录用户
        Integer loginNumYesterday = logMapper.loginNumToday(yesterday);
        Integer activeUsersTodayRate = activeUsersToday == 0 ? 0 : (yesterdayRegisters + loginNumYesterday - activeUsersToday) / activeUsersToday * 100;

        //昨日日活
        //前天登录用户
        Integer loginNumTheDayBeforeYesterday = logMapper.loginNumToday(theDayBeforeYesterday);
        //前天注册用户
        Integer theDayBeforeYesterdayRegisters = logMapper.registerNumToday(theDayBeforeYesterday);
        int activeUsersYesterday = newUsersYesterday + loginNumYesterday;
        Integer activeUsersYesterdayRate = activeUsersYesterday == 0 ? 0 : (theDayBeforeYesterdayRegisters + loginNumTheDayBeforeYesterday - activeUsersYesterday) / activeUsersYesterday * 100;


        //昨日日活同比
        //过去一周用户平均在线时间
        //1.找出过去一周登录的用户
        AnalysisVo vo = new AnalysisVo();
        vo.setCumulativeUsers(cumulativeUsers);
        vo.setActivePassMonth(activePassMonth);
        vo.setActivePassWeek(activePassWeek);
        vo.setNewUsersToday(newUsersToday);
        vo.setNewUsersTodayRate(newUsersTodayRate);
        vo.setLoginTimesToday(loginTimesToday);
        vo.setLoginTimesTodayRate(loginTimesTodayRate);
        vo.setActiveUsersToday(activeUsersToday);
        vo.setActiveUsersTodayRate(activeUsersTodayRate);
        vo.setActiveUsersYesterday(activeUsersYesterday);
        vo.setActiveUsersYesterdayRate(activeUsersYesterdayRate);
        vo.setUseTimePassWeek(33);
        return vo;
    }

    /**
     * 仪表板数据
     *
     * @param type      类型 类型 101 新增 102 活跃用户 103 次日留存率
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return {@link ResponseEntity}
     */
    public ResponseEntity getDashboardData(Long startDate, Long endDate, String type) {
        SimpleDateFormat format = new SimpleDateFormat(RC.GENERAL_DATE_FORMAT);
        String start = format.format(startDate);

        String end = format.format(endDate);

        //计算去年开始日期
        String lastYearNum = String.valueOf(Integer.parseInt(start.split("-")[0]) - 1);
        String lastYearStart = lastYearNum + "-" + start.split("-")[1] + "-" + start.split("-")[2];
        //计算去年结束日期
        String endYear = String.valueOf(Integer.parseInt(end.split("-")[0]) - 1);
        String lastYearEnd = endYear + "-" + end.split("-")[1] + "-" + end.split("-")[2];
        //获取范围日期内今年的数据
        LambdaQueryWrapper<Analysis> thisYearWrapper = new LambdaQueryWrapper<>();
        thisYearWrapper.ge(Analysis::getRecordDate, start).le(Analysis::getRecordDate, end);

        LambdaQueryWrapper<Analysis> lastYearWrapper = new LambdaQueryWrapper<>();
        lastYearWrapper.ge(Analysis::getRecordDate, lastYearStart).le(Analysis::getRecordDate, lastYearEnd);

        //获取今年数据
        List<Analysis> thisYears = analysisMapper.selectList(thisYearWrapper);
        //获取去年数据
        List<Analysis> lastYears = analysisMapper.selectList(lastYearWrapper);
        //处理数据 ,判断数据获取类型
        List<DayDataVo> thisYear = new ArrayList<>();
        List<DayDataVo> lastYear = new ArrayList<>();
        if ("101".equals(type)) {
            thisYear = thisYears.stream().map((ana) -> {
                DayDataVo vo = new DayDataVo();
                String title = format.format(ana.getRecordDate()).split("-")[2];
                Integer amount = ana.getNumRegistered();
                vo.setTitle(title);
                vo.setAmount(amount);
                return vo;
            }).collect(Collectors.toList());
            lastYear = lastYears.stream().map((ana) -> {
                DayDataVo vo = new DayDataVo();
                String title = format.format(ana.getRecordDate()).split("-")[2];
                Integer amount = ana.getNumRegistered();
                vo.setTitle(title);
                vo.setAmount(amount);
                return vo;
            }).collect(Collectors.toList());
        } else if ("102".equals(type)) {
            thisYear = thisYears.stream().map((ana) -> {
                DayDataVo vo = new DayDataVo();
                String title = format.format(ana.getRecordDate()).split("-")[2];
                Integer amount = ana.getNumActive();
                vo.setTitle(title);
                vo.setAmount(amount);
                return vo;
            }).collect(Collectors.toList());
            lastYear = lastYears.stream().map((ana) -> {
                DayDataVo vo = new DayDataVo();
                String title = format.format(ana.getRecordDate()).split("-")[2];
                Integer amount = ana.getNumActive();
                vo.setTitle(title);
                vo.setAmount(amount);
                return vo;
            }).collect(Collectors.toList());
        } else {
            //次日留存率
            thisYear = thisYears.stream().map((ana) -> {
                DayDataVo vo = new DayDataVo();
                String title = format.format(ana.getRecordDate()).split("-")[2];
                Integer amount = ana.getNumRetention1d();
                vo.setTitle(title);
                vo.setAmount(amount);
                return vo;
            }).collect(Collectors.toList());
            lastYear = lastYears.stream().map((ana) -> {
                DayDataVo vo = new DayDataVo();
                String title = format.format(ana.getRecordDate()).split("-")[2];
                Integer amount = ana.getNumRetention1d();
                vo.setTitle(title);
                vo.setAmount(amount);
                return vo;
            }).collect(Collectors.toList());


        }
        YearDateVo vo = new YearDateVo();
        vo.setThisYear(thisYear);
        vo.setLastYear(lastYear);
        return ResponseEntity.ok(vo);
    }

    public DistributionVo getDistribution(Long startDate, Long endDate) {
        //构建vo对象
        DistributionVo vo = new DistributionVo();
        List<IndustryDistribution> industryDistribution = distributionProperties.getIndustryDistribution().stream().map(IndustryDistribution::init).collect(Collectors.toList());
        List<AgeDistribution> ageDistribution = distributionProperties.getAgeDistribution().stream().map(AgeDistribution::init).collect(Collectors.toList());
        List<GenderDistribution> genderDistribution = distributionProperties.getGenderDistribution().stream().map(GenderDistribution::init).collect(Collectors.toList());
        List<LocalDistribution> localDistribution = distributionProperties.getLocalDistribution().stream().map(LocalDistribution::init).collect(Collectors.toList());
        List<LocalTotal> localTotal = distributionProperties.getLocalTotal().stream().map(LocalTotal::init).collect(Collectors.toList());

        vo.setIndustryDistribution(industryDistribution);
        vo.setAgeDistribution(ageDistribution);
        vo.setGenderDistribution(genderDistribution);
        vo.setLocalDistribution(localDistribution);
        vo.setLocalTotal(localTotal);
        return userInfoApi.getDistribution(startDate, endDate, vo);
    }
}
